// dht11.c
#include "stm32f1xx_hal.h"
#include "tim.h"
#include "dht11.h"

#define DHT11_PIN  GPIO_PIN_6
#define DHT11_PORT GPIOA
#define DHT11_TIMEOUT 100

void DHT11_Delay_us(uint16_t us) {
    __HAL_TIM_SET_COUNTER(&htim3, 0);
    HAL_TIM_Base_Start(&htim3);
    while (__HAL_TIM_GET_COUNTER(&htim3) < us);
    HAL_TIM_Base_Stop(&htim3);
}

void DHT11_SetInput(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DHT11_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

void DHT11_SetOutput(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DHT11_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

void DHT11_Start(void){
    DHT11_SetOutput();
    HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
    HAL_Delay(18);  // 18ms低电平
    HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
    DHT11_Delay_us(30);  // 20-40us高电平
    DHT11_SetInput();
}

uint8_t DHT11_Check(void){
    uint8_t retry = 0;
    // 等待80us低电平响应
    while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) && retry < DHT11_TIMEOUT){
        retry++;
        DHT11_Delay_us(1);
    }
    if(retry >= DHT11_TIMEOUT) return 1;

    retry = 0;
    // 等待80us高电平响应
    while(!HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) && retry < DHT11_TIMEOUT){
        retry++;
        DHT11_Delay_us(1);
    }
    return (retry >= DHT11_TIMEOUT);
}

uint8_t DHT11_Read_Bit(void){
    uint8_t retry = 0;
    // 等待50us低电平开始
    while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) && retry < DHT11_TIMEOUT){
        retry++;
        DHT11_Delay_us(1);
    }

    retry = 0;
    // 等待高电平
    while(!HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) && retry < DHT11_TIMEOUT){
        retry++;
        DHT11_Delay_us(1);
    }

    DHT11_Delay_us(40);  // 延迟40us判断高低电平
    return HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN);
}

uint8_t DHT11_Read_Byte(void){
    uint8_t i, dat = 0;
    for(i=0; i<8; i++){
        dat <<= 1;  // 左移一位
        if(DHT11_Read_Bit()) dat |= 1;
    }
    return dat;
}

uint8_t DHT11_Read_Data(uint8_t* temperature, uint8_t* humidity){
    uint8_t buffer[5] = {0};
    uint8_t i;

    DHT11_Start();
    if(DHT11_Check() == 0){
        for(i=0; i<5; i++){
            buffer[i] = DHT11_Read_Byte();
        }

        // 校验数据
        if((buffer[0] + buffer[1] + buffer[2] + buffer[3]) == buffer[4]){
            *humidity = buffer[0];    // 湿度整数部分
            *temperature = buffer[2]; // 温度整数部分
            return 0;  // 成功
        }
    }
    return 1;  // 失败
}
